// SPDX-License-Identifier: MIT
// SPDX-FileCopyrightText: 2022 Ivan Baidakou

#pragma once

#include "definitions.hpp"
#include <cstddef>

namespace rotor_light {

struct TimeEvent {
  TimeEvent() = default;
  TimeEvent(TimeEvent &&) = delete;
  TimeEvent(const TimeEvent &) = delete;

  TimeEvent &operator=(const TimeEvent &other);
  Callback callback = nullptr;
  void *data;
  TimePoint when = 0;
};

struct PlannerBase;

struct EventConsumer {
  void call_next();
  operator bool() const;
  ~EventConsumer();

private:
  friend struct PlannerBase;
  EventConsumer(TimePoint deadline, PlannerBase *watchdog);
  TimePoint deadline;
  PlannerBase *watchdog;
  int32_t index;
};

struct PlannerBase {
  PlannerBase(TimeEvent *events, int32_t events_count);
  PlannerBase(const PlannerBase &) = delete;
  PlannerBase(PlannerBase &&) = delete;
  bool add_event(TimePoint when, Callback, void *data);
  void remove_event(TimePoint when, void *data);
  EventConsumer consume(TimePoint deadline);
  TimePoint next_event();

private:
  friend struct EventConsumer;
  void commit(size_t index);
  TimeEvent *events;
  int32_t events_count;
  int32_t last_event;
};

template <size_t TimeEventsCount> struct Planner : PlannerBase {
  static_assert(TimeEventsCount > 0, "at least one event have to be allocated");
  Planner() : PlannerBase(events_holder, TimeEventsCount){};
  TimeEvent events_holder[TimeEventsCount];
};

} // namespace rotor_light
